<?php

namespace App\Models;

use App\Events\UploadIdCardEvent;
use App\Exceptions\GeneralException;
use App\Facades\MoneyPlatformRequestFacade;
use App\Facades\SamLogFacade;
use App\Library\Bank\BankCode;
use App\Library\String\Strings;
use Carbon\Carbon;
use Doctrine\DBAL\Schema\Schema;
use \Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Storage;
use Jacobcyl\AliOSS\AliOssAdapter;
use Overtrue\LaravelPinyin\Facades\Pinyin;
use phpDocumentor\Reflection\Types\Integer;
use phpDocumentor\Reflection\Types\Self_;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Tymon\JWTAuth\Facades\JWTAuth;
use Exception;

/**
 * Class User
 * Description:用户模型
 * Author: Sam
 * DateTime: 2019/1/2 10:24
 *
 * @package App\Models
 * @property int $id 主键
 * @property string $phone_num 手机
 * @property string $password
 * @property string $avatar 用户头像
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 * @property string $nfsp_user_id nfsp用户id
 * @property-read mixed $avatar_show
 * @property-read mixed $cert_gov
 * @property-read mixed $cert_no
 * @property-read mixed $domicile_address
 * @property-read mixed $real_name
 * @property-read mixed $valid
 * @property-read mixed $valid_date_end
 * @property-read mixed $wechat
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User newModelQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User newQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User query()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereAvatar($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereNfspUserId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User wherePassword($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User wherePhoneNum($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereUpdatedAt($value)
 * @mixin \Eloquent
 * @property-read \App\Models\UserGlobal $globalStatus
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UserCertOcr[] $validCert
 * @property-read mixed $request_channel
 * @property-read bool $loan_able
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\LoanApply[] $loanApply
 * @property-read \App\Models\UserLoanRequest $recentlyLoanRequest
 * @property string|null $source 渠道来源
 * @property-read \UserGlobal|\Illuminate\Database\Eloquent\Model|object|null $user_global
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereSource($value)
 * @property int|null $using_bank_card 用户当前使用的银行卡
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UserLoanRequest[] $loanRequest
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereUsingBankCard($value)
 * @property-read bool|false|string $age
 * @property-read \App\Models\UserLoginLog $loginLogRelation
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\UserCertOcr[] $userCert
 * @property-read \App\Models\UserWechat $userWechatRelation
 * @property int|null $marry_status 婚姻状态：0未婚 1已婚
 * @property int|null $old_xinliu_id 旧卡贷新流用户id
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereMarryStatus($value)
 * @property-read string|$phone_num_sha
 * @property string|null $r360_check 融360撞库标识
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User wherePhoneNumSha($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereR360Check($value)
 * @property string|null $old_kskd_user_id
 * @property-read mixed $edu
 * @property-read bool|string $sex
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\User whereOldKskdUserId($value)
 */
class User extends Authenticatable implements JWTSubject
{
    //手机号平台是否存在
    const MOBILE_EXISTS_ONE = 1; //已存在
    const MOBILE_EXISTS_TWO = 2; //未存在

    const FULL_STATUS_COMMIT = 1, FULL_STATUS_RISK = 2,FULL_STATUS_CREDIT = 3,FULL_STATUS_WAIT_LOAN=4;
    static $FULL_STATUS = [
        self::FULL_STATUS_COMMIT => '进件',
        self::FULL_STATUS_RISK => '风控',
        self::FULL_STATUS_CREDIT => '授信',
        self::FULL_STATUS_WAIT_LOAN => '待放款',
    ];

    static $FULL_STATUS_DETAIL = [
        self::FULL_STATUS_COMMIT => [
            UserAuthStepEventLog::STEP_OCR           => '实名认证',
            UserAuthStepEventLog::STEP_FACE          => '人脸识别',
            UserAuthStepEventLog::STEP_INFO          => '个人信息',
            UserAuthStepEventLog::STEP_BIND_CASH     => '储蓄卡',
            UserAuthStepEventLog::STEP_BIND_CREDIT   => '信用卡',
            UserAuthStepEventLog::STEP_PHONE_SERVICE => '通话详单',
            UserAuthStepEventLog::STEP_ZHIMA         => '芝麻信用',
        ],
        self::FULL_STATUS_RISK   => [
            UserLoanRequest::STATUS_RISK_FAILED => '风控失败',
            UserLoanRequest::STATUS_RISK_REJECT => '风控拒绝',
            UserLoanRequest::STATUS_WAIT_FOR_RISK => '风控中'
        ],
        self::FULL_STATUS_CREDIT => [
            UserLoanRequest::STATUS_APPLY => '等待授信',
            UserLoanRequest::STATUS_FAILD => '授信拒绝'
        ],
        self::FULL_STATUS_WAIT_LOAN    => [
            UserLoanRequest::STATUS_TIME_OUT => '时限1',
            UserLoanRequest::STATS_RESTART => '时限2',
        ],
//        5 => [
//            UserLoanRequest::STATUS_TIME_OUT => '时限2'
//        ],
    ];

    /*
     * 新用户状态 1=未提单  2=提单中
     * */
    const NEW_USER_STATUS_NO = 1, NEW_USER_STATUS_ING = 2;

    static $NEW_USE_STATUS = [
        self::NEW_USER_STATUS_NO  => '未进件',
        self::NEW_USER_STATUS_ING => '进件'
    ];

    /**
     * 联登的渠道来源
     */
    const SOURCE_SMALL_BLACK_FISH = 41001;
    const SOURCE_51_CREDIT_CARD = 41002;
    const SOURCE_SHENG_BAI = 41003;
    const SOURCE_YANG_QIAN_GUAN = 41004;
    const SOURCE_JU_HAO_DAI = 41005;
    const SOURCE_BAO_JIE = 41006;
    const SOURCE_BAO_ZHAO_QIAN = 41007;
    const SOURCE_HELP_WALLET= 41008;

    const SOURCE_LIST = [
        self::SOURCE_SMALL_BLACK_FISH => '小黑鱼连登',
        self::SOURCE_51_CREDIT_CARD => '51信用卡管家',
        self::SOURCE_SHENG_BAI => '省呗连登',
        self::SOURCE_YANG_QIAN_GUAN => '洋钱罐连登',
        self::SOURCE_JU_HAO_DAI => '聚好贷',
        self::SOURCE_BAO_JIE => '保街连登',//借云
        self::SOURCE_BAO_ZHAO_QIAN => '包找钱',
        self::SOURCE_HELP_WALLET => '助力钱包'
    ];

    /**
     * 可以被批量赋值的属性。
     *
     * @var array
     */
    protected $fillable = [
        'phone_num',
        'password',
        'avatar',
        'created_at',
        'updated_at',
        'nfsp_user_id',
        'phone_num_sha',
        'source',
        'phone_num_md5',
        'old_xinliu_id'
    ];

    /**
     * 定义不显示出来的字段
     * @var array
     */
    protected $hidden = [
        'avatar',
        'password',
    ];

    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier()
    {
        return $this->getKey();
    }

    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims()
    {
        return [];
    }

    /**
     * Description:设置密码的时候对密码进行加密
     * Author: Sam
     * DateTime: 2018/12/28 18:11
     * @param $value
     */
    public function setPasswordAttribute($value)
    {
        $this->attributes['password'] = bcrypt($value);
        $this->attributes['phone_num_sha'] = hash('SHA256',$this->attributes['phone_num']);
        $this->attributes['phone_num_md5'] = md5($this->attributes['phone_num']);
    }

    /**
     * Description: 获取用户头像
     * Author: liuju
     * DateTime: 2019-01-05 11:20
     * @return string
     */
    public function getAvatarShowAttribute()
    {
        if (!$this->avatar) {
            return '';
        }
        if (strpos($this->avatar, 'http') !== false) {
            return $this->avatar;
        }

        if (Storage::disk('oss')->exists($this->avatar)) {
            return Storage::disk('oss')->signUrl($this->avatar);
        }
        return '';
    }

    /**
     * Description: 用户是否实名认证
     * Author: liuju
     * DateTime: 2018-12-28 18:21
     * @return mixed
     */
    public function getValidAttribute()
    {
        return UserCertOcr::where('user_id', $this->id)->where('is_valid', UserCertOcr::IS_VALID)->orderByDesc('id')->first();
    }

    /**
     * Description:获取用户当前业务线的渠道号
     * Author: Sam
     * DateTime: 2019/1/6 16:14
     * @return mixed
     */
    public function getRequestChannelAttribute()
    {
        return UserLoanRequest::where('user_id', $this->id)->orderByDesc('created_at')->value('channel');
    }

    /**
     * Description: 获取用户是否绑定过微信
     * Author: liuju
     * DateTime: 2019-01-03 19:58
     * @return mixed
     */
    public function getWechatAttribute()
    {
        return UserWechat::where('user_id', $this->id)->first();
    }

    /**
     * Description:获取用户姓名
     * Author: Sam
     * DateTime: 2019/1/2 16:32
     * @return mixed
     */
    public function getRealNameAttribute()
    {
        return UserCertOcr::where(['user_id' => $this->id, 'is_valid' => UserCertOcr::IS_VALID])->orderByDesc('created_at')->value('name');
    }

    /**
     * Description:获取用户身份证号
     * Author: Sam
     * DateTime: 2019/1/2 16:50
     * @return mixed
     */
    public function getCertNoAttribute()
    {
        return UserCertOcr::where(['user_id' => $this->id, 'is_valid' => UserCertOcr::IS_VALID])->value('num');
    }

    /**
     * Description:获取用户性别
     * Author: Sam
     * DateTime: 2019-03-01 18:02
     * @return bool|string
     */
    public function getSexAttribute()
    {
        $sex = substr($this->cert_no, -2, 1);
        $res = $sex%2; //0是女 1是男

        return empty($res)?2:1; //1男2女
    }

    /**
     * Description:获取用户教育程度
     * Author: Sam
     * DateTime: 2019-03-01 18:14
     * @return mixed
     */
    public function getEduAttribute()
    {
        return UserInfo::where('user_id', $this->id)->orderByDesc('created_at')->value('education');
    }


    /**
     * Description:获取用户身份证有效期
     * Author: Sam
     * DateTime: 2019/1/2 16:52
     * @return mixed
     */
    public function getValidDateEndAttribute()
    {
        return UserCertOcr::where(['user_id' => $this->id, 'is_valid' => UserCertOcr::IS_VALID])->orderByDesc('created_at')->value('valid_date_end');
    }

    /**
     * Description:获取用户身份证签发机关代码
     * Author: Sam
     * DateTime: 2019/1/3 14:10
     * @return mixed
     */
    public function getCertGovAttribute()
    {
//        return UserCertOcr::where(['user_id' => $this->id, 'is_valid' => UserCertOcr::IS_VALID])->value('issue_gov_code');
        return UserCertOcr::where(['user_id' => $this->id, 'is_valid' => UserCertOcr::IS_VALID])->orderByDesc('created_at')->value('issuing_authority');

    }

    /**
     * Description:获取用户身份证地址
     * Author: Sam
     * DateTime: 2019/1/3 14:11
     * @return mixed
     */
    public function getDomicileAddressAttribute()
    {
        return UserCertOcr::where(['user_id' => $this->id, 'is_valid' => UserCertOcr::IS_VALID])->orderByDesc('created_at')->value('domicile_address');
    }


    /**
     * Description: 获取用户全局状态
     * Author: liuju
     * DateTime: 2019-01-09 17:51
     * @return UserGlobal|\Illuminate\Database\Eloquent\Model|object|null
     */
    public function getUserGlobalAttribute()
    {
        return UserGlobal::where('uid', $this->id)->first();
    }

    /**
     * Description:获取用户年龄
     * Author: Sam
     * DateTime: 2019-01-26 12:54
     * @return bool|false|string
     */
    public function getAgeAttribute()
    {
        $birth_year = substr($this->cert_no, 6, 4);
        $now_year = date('Y');
        return $now_year - $birth_year;
    }

    /**
     * Description: 用户信息同步
     * Author: Sam
     * DateTime: 2019-01-29 10:58
     * @param $user_id "用户id"
     * @param $bank_card_id "银行卡id"
     * @param $user_info_id "用户信息id"
     * @param $amount "风控返回额度"
     * @return mixed
     * @throws GeneralException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function userSync($user_id, $bank_card_id, $user_info_id, $amount)
    {
        $user = User::find($user_id);
        $data['realName'] = $user->real_name;
        $data['englishName'] = strtoupper(Pinyin::permalink($user->real_name, ''));
        $data['certType'] = '1';
        $data['certNo'] = $user->cert_no;
        $data['gender'] = $user->sex;//性别 19-03-21新增
        $data['certValidity'] = $user->valid_date_end == '长期' ? 'LONG' : Carbon::parse($user->valid_date_end)->format('Y-m-d');
        $data['certGovernment'] = $user->cert_gov;
        $data['certNation'] = '';
        $data['certAddr'] = $user->domicile_address; //19-02-27添加
        $data['maritalStatus'] = self::getMaritalStatus($user->age);//婚姻状况
        $data['email'] = self::createEmail(strtolower(Pinyin::permalink($user->real_name, '')));//电子邮箱
        $data['liveCondition'] = '99';//居住状况
        $six = substr($user->cert_no, 0, 6);
        $address_code = config('issue_gov_code');
        $address_data = [];
        $match = 0;
        foreach ($address_code as $v) {
            if ($v['code'] == $six) {
                $address_data = $v;
                $match = 1;
                break;
            }
        }
        if ($match) { //先用身份证前6位匹配
            $data['liveProvince'] = $address_data['province'];
            $data['liveCity'] = $address_data['city'];
            $data['liveArea'] = $address_data['district'];
        } else {
            $address_data = Strings::getAddressCut($user->domicile_address);
            $data['liveProvince'] = $address_data['province'];
            $data['liveCity'] = $address_data['city'];
            $data['liveArea'] = $address_data['area'];
        }
        $data['address'] = $user->domicile_address;
        $data['postCode'] = '';
        $bank_card_info = UserBankCard::find($bank_card_id);
        $data['loanBankCode'] = BankCode::getBankCode($bank_card_info->bank_name);
        $data['loanBankName'] = $bank_card_info->bank_name;
        $data['loanBankCardNo'] = $bank_card_info->card_num;
        $data['loanBindPhoneNo'] = $bank_card_info->phone_num;
        $data['bankLineNumber'] = '';
        $user_info = UserInfo::find($user_info_id);
        $data['educationalLevel'] = $user_info->education;
        $data['contactName'] = $user_info->linkman_first;
        $data['contactPhoneNo'] = $user_info->linkman_first_phone;
        $data['contactRelation'] = $user_info->linkman_first_relation;
        $data['contactName2'] = $user_info->linkman_second; //19-02-27添加
        $data['contactPhoneNo2'] = $user_info->linkman_second_phone; //19-02-27添加
        $data['contactRelation2'] = $user_info->linkman_second_relation; //19-02-27添加
        $data['supportPopulation'] = '0'; //供养人口 19-03-21 添加
        $data['positionOpt'] = self::createPosition($user->age); //社会身份
        $data['companyName'] = $user_info->company;
        $data['companyAddress'] = $user_info->work_address;
        $data['companyPhone'] = $user_info->work_phone;
        $data['salary'] = self::createSalary($amount);//月薪
        $data['workDuration'] = self::createWorkDuration($user->age);//工作年限 19-03-21
        $data['companyCategory'] = '12';
        $industry = $user_info->profession;//因为要兼容新旧APP 所以不改字段名
        if((int)$industry>12){ //兼容旧APP
            $industry = '12';
        }
        $data['industry'] = $industry;
        $data['protocolNo'] = $bank_card_info->hold_agreement_num;
        if (!empty($bank_card_info)) {
            if ($bank_card_info->created_at instanceof Carbon) {
                $data['protocolDate'] = $bank_card_info->created_at->toDateTimeString();
            } else {
                $data['protocolDate'] = $bank_card_info->created_at;
            }
        } else {
            $data['protocolDate'] = '';
        }
        $data['healthCondition'] = '01';//健康状况
        foreach ($data as $k => $v){
            if(in_array($k,['protocolDate','certValidity'])){
                continue;
            }
            $data[$k] = Strings::specialString($v);//过滤掉特殊字符
        }
        $exist = UserSyncInfo::where('user_id',$user_id)->first();
        if(!$exist){
            try{
                $sync_info = $data;
                $sync_info['user_id'] = $user_id;
                UserSyncInfo::query()->create($sync_info);
            }catch (Exception $e){
                SamLogFacade::debug($e->getMessage());
                throw new GeneralException($e->getMessage());
            }
        }
        $result = MoneyPlatformRequestFacade::userSync($data);
        SamLogFacade::debug('用户信息同步参数' . json_encode($data, JSON_UNESCAPED_UNICODE));
        SamLogFacade::debug('用户信息响应参数' . json_encode($result, JSON_UNESCAPED_UNICODE));
        if ($result['code'] !== '01') {
            SamLogFacade::debug('用户信息同步失败返回：' . $result['message']);
            if($result['message'] == '此单不允许换放款卡'){
                $loan = UserLoanRequest::where(['user_id'=>$user_id,'user_base_info_id'=>$user_info_id,'cash_card_choice_id'=>$bank_card_id])->first();
                $loan->status = 7;
                $loan->save();
                SamLogFacade::debug("用户【{$user_id}】因为 {$result['message']}授信【{$loan->id}】状态改为7");
                return false;
            }
//            $list = json_encode(['user_id' => $user_id, 'bank_card_id' => $bank_card_id, 'user_info_id' => $user_info_id, 'amount' => $amount]);
//            Redis::lPush('syncFail', $list);
            return false;
        }
        $user->nfsp_user_id = $result['data']['userId'];
        $user->marry_status = $data['maritalStatus'];
        $user->save();
        self::UpdateUsingBankCard($bank_card_info);
        event(new UploadIdCardEvent($user));
        return $result;
    }

    /**
     * Description: 获取用户信息
     * Author: liuju
     * DateTime: 2019-01-05 11:24
     * @return array
     */
    public static function getCurrentUserDetailByApp($user)
    {
        $hashKey = self::getHashKey();
        $key = $user->phone_num . ':token';
        $arr = [
            'phone_num' => $user->phone_num,
            'avatar_url' => $user->avatarShow,
            'is_ocr' => $user->valid ? true : false,
            'global_status' => $user->userGlobal ? $user->userGlobal->global_status : '0',
        ];
        if (!Request::route()->named('api_v10.login', 'api_v10.register')) {
            $arr['token'] = Redis::hGet($hashKey, $key);
        }
        return $arr;
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     * @author luwei
     * @date 2019-01-05 15:36
     */
    public function validCert()
    {
        return $this->hasMany(UserCertOcr::class, 'user_id', 'id')->where('is_valid', UserCertOcr::IS_VALID);
    }

    /**
     * 最近的一条授信申请关联
     * @author luwei
     * @date 2019-01-07 16:37
     */
    public function recentlyLoanRequest()
    {
        return $this->hasOne(UserLoanRequest::class, 'user_id', 'id')->orderBy('id', 'desc');
    }

    public function loanRequest()
    {
        return $this->hasMany(UserLoanRequest::class, 'user_id', 'id');
    }

    public function loanApply()
    {
        return $this->hasMany(LoanApply::class, 'user_id', 'id');
    }

    /**
     * 登录流水日志关联
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     * @author luwei
     * @date 2019-01-12 19:52
     */
    public function loginLogRelation()
    {
        return $this->hasOne(UserLoginLog::class, 'user_id', 'id');
    }

    /**
     * 用户微信关联
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     * @author luwei
     * @date 2019-01-12 20:05
     */
    public function userWechatRelation()
    {
        return $this->hasOne(UserWechat::class, 'uid', 'id');
    }

    /**
     * 用户身份证关联
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     * @author luwei
     * @date 2019-01-12 20:35
     */
    public function userCert()
    {
        return $this->hasMany(UserCertOcr::class, 'user_id', 'id');
    }

    /**
     * 用户列表
     * @param bool $status 父状态
     * @param bool $childStatus 子状态
     * @param $name
     * @param int $pageSize
     * @return mixed
     * @throws GeneralException
     * @author luwei
     * @date 2019-01-07 21:06
     */
    public static function userList($status = false, $childStatus = false, $name, $pageSize = 10) {
        $data   = self::userListData($status,$childStatus,$name,$pageSize);
        $return = [];
        foreach ($data as $v) {
            //处理授信信息
            $loanInfo = UserLoanRequest::getResource($v);
            $status   = $loanInfo['status'];
            unset($loanInfo['status']);
            //历史借次
            $count    = LoanApply::byUid($v->user_id)->where('loan_status', LoanApply::LOAN_STATUS_SUCCESS)->count();
            $text = self::dealDetailStatus($status, $loanInfo['id']);
            $detailStatusText = $text['detail_status'];
            $statusText = $text['status'];

            $return[] = [
                'id'                 => $v->id,
                'loan_info'          => $loanInfo,
                'count'              => $count,
                'phone'              => optional(optional($v->user)->phone_num),
                'source'             => optional(optional($v->user)->source),
                'status'             => $status,
                'status_text'        => $statusText,
                'detail_status_text' => $detailStatusText
            ];
        }
        return [
            'data'  => $return,
            'total' => $data->total()
        ];
    }

    /**
     * 用户列表源数据
     * @param $status
     * @param $childStatus
     * @param $name
     * @param $pageSize
     * @param bool $isExport
     * @return UserLoanRequest|\Generator|\Illuminate\Contracts\Pagination\LengthAwarePaginator|\Illuminate\Database\Eloquent\Builder|mixed
     * @author luwei
     * @date 2019-03-11 18:23
     */
    public static function userListData($status, $childStatus, $name, $pageSize, $isExport = false){
        $data   = UserLoanRequest::with('user', 'userCert', 'stepLog')->where('current', 1)
            ->when(($status), function ($query) use ($status, $childStatus) {
                $con = ['status' => $status];
                if ($status == self::FULL_STATUS_COMMIT) {
                    $childCon = ['type' => $childStatus];
                    $query->where($con)->whereHas('stepLog', function ($q) use ($childCon) {
                        $q->whereIsCurrent(UserAuthStepEventLog::CURRENT_STEP_YES)->where($childCon);
                    });
                }else{
                    $childCon = ['status' => $childStatus];
                    $query->where($childCon);
                };
            }, function ($query) {
                //没有搜索状态时  取出该用户所需状态数据
                $statusCon = [
                    UserLoanRequest::STATUS_UN_APPLY,
                    UserLoanRequest::STATUS_APPLY,
                    UserLoanRequest::STATUS_FAILD,
                    UserLoanRequest::STATUS_TIME_OUT,
                    UserLoanRequest::STATS_RESTART,
                    UserLoanRequest::STATUS_RISK_FAILED,
                    UserLoanRequest::STATUS_RISK_REJECT,
                    UserLoanRequest::STATUS_WAIT_FOR_RISK,
                ];
                $query->whereIn('status', $statusCon);
            })
            ->when($name, function ($query) use ($name) {
                $query->whereHas('userCert', function ($q) use ($name) {
                    $q->where('name', 'like', '%' . $name . '%');
                });
            });
            if(!$isExport){
                $data = $data->paginate($pageSize);
            }else{
                $data = $data->cursor();
            }
            return $data;
    }

    /**
     * 借款详情
     * @param $userId
     * @return array
     * @throws GeneralException
     * @author luwei
     * @date 2019-01-12 15:47
     */
    public static function dealLoanDetail($userId)
    {
        $con = [
            UserLoanRequest::STATUS_UN_APPLY,
            UserLoanRequest::STATUS_APPLY,
            UserLoanRequest::STATUS_SUCCESS,
            UserLoanRequest::STATUS_FAILD,
            UserLoanRequest::STATUS_TIME_OUT,
            UserLoanRequest::STATUS_WAIT_FOR_RISK,
            UserLoanRequest::STATUS_RISK_FAILED,
            UserLoanRequest::STATUS_RISK_REJECT,
        ];
        $loanRequest = UserLoanRequest::with(['user', 'baseInfo', 'userCert', 'bankCard', 'creditCard', 'device', 'user.userWechatRelation'])
            ->byUid($userId)
            ->orderBy('id', 'desc')
            ->whereIn('status', $con)
            ->paginate(10);
        $info = [];
        foreach ($loanRequest as $loan) {
            $status = $loan->status;

//            $status = self::dealSpecStatus($status);
            $text = self::dealDetailStatus($status, $loan->id);
            $detailStatusText = $text['detail_status'];
            $statusText = $text['status'];

            $openId = optional($loan->user->userWechatRelation)->open_id;
            $baseInfo = [
                'loan_id' => $loan->id,
                'name' => optional($loan->userCert)->name,
                'phone' => $loan->user->phone_num,
                'status' => $statusText,
                'detail_status' => $detailStatusText,
                'user_id' => $userId,
                'source' => $loan->user->source,
                'open_id' => $openId
            ];
            $realInfo = [];
            if ($loan->userCert) {
                $realInfo = [
                    'card_num' => optional($loan->userCert)->num,
                    'issuing_authority' => optional($loan->userCert)->issuing_authority,
                    'domicile_address' => optional($loan->userCert)->domicile_address,
                    'valid_at' => optional($loan->userCert)->valid_date_begin . '至' . optional($loan->userCert)->valid_date_end
                ];
            }

            $userInfo = [];
            if ($loan->baseInfo) {
                $userInfo = [
                    'education' => optional($loan->baseInfo)->edu_str,
                    'company' => optional($loan->baseInfo)->company,
                    'work_address' => optional($loan->baseInfo)->work_address,
                    'work_phone' => optional($loan->baseInfo)->work_phone,
                    'linkman_first' => optional($loan->baseInfo)->linkman_first,
                    'linkman_first_relation' => UserInfo::$USER_RELATION[optional($loan->baseInfo)->linkman_first_relation],
                    'linkman_first_phone' => optional($loan->baseInfo)->linkman_first_phone,
                    'linkman_second' => optional($loan->baseInfo)->linkman_second,
                    'linkman_second_relation' => UserInfo::$USER_RELATION[optional($loan->baseInfo)->linkman_second_relation],
                    'linkman_second_phone' => optional($loan->baseInfo)->linkman_second_phone,
                ];
            }
            //银行卡-信用卡信息
            $bankCardInfo = $creditCardInfo = [];
            if ($loan->bankCard) {
                $bankCardInfo = [[
                    'name' => $loan->bankCard->bank_name_show,
                    'bank_card_num' => $loan->bankCard->card_num
                ]];
            }
            if ($loan->creditCard) {
                $creditCardInfo = [[
                    'name' => $loan->creditCard->bank_name_show,
                    'bank_card_num' => $loan->creditCard->card_num
                ]];
            }

            //设备信息
            $deviceInfo = [];
            if ($loan->device) {
                $deviceInfo = [
                    'ip' => $loan->device->ip,
                    'device_type' => $loan->device->device_type,
                    'gps' => $loan->device->gps,
                    'device' => $loan->device->device,
                    'device_mac' => $loan->device->device_mac,
                    'device_os' => $loan->device->device_os,
                    'device_imei' => $loan->device->device_imei,
                    'device_uuid' => $loan->device->device_uuid,
                    'device_app' => $loan->device->device_app,
                    'zhima' => '',
                    'phone' => '',
                    'face' => ''
                ];
            }

            $info[] = [
                'base_info' => $baseInfo,
                'real_info' => $realInfo,
                'user_info' => $userInfo,
                'bank_card_info' => $bankCardInfo,
                'credit_card_info' => $creditCardInfo,
                'device_info' => $deviceInfo,
                'loan_time' => $loan->created_at->format('Y-m-d')
            ];
        }
        return [
            'data' => $info,
            'total' => $loanRequest->total()
        ];
    }

    /**
     * 处理状态
     * @param $status
     * @param int $loanId
     * @return mixed
     * @author luwei
     * @date 2019-01-07 21:22
     * @throws GeneralException
     */
    protected static function dealDetailStatus($status, $loanId = 0)
    {

        switch ($status) {
            case UserLoanRequest::STATUS_UN_APPLY:
                $log = UserAuthStepEventLog::byLoanId($loanId)->where('is_current', UserAuthStepEventLog::CURRENT_STEP_YES)->first();
                if (!$log) {
                    $return = [
                        'status' => '异常',
                        'detail_status' => '异常'
                    ];
                } else {
                    $return = [
                        'status' => self::$FULL_STATUS[self::FULL_STATUS_COMMIT],
                        'detail_status' => self::$FULL_STATUS_DETAIL[self::FULL_STATUS_COMMIT][$log->type]
                    ];
                }
                break;
            case UserLoanRequest::STATUS_RISK_FAILED:
            case UserLoanRequest::STATUS_RISK_REJECT:
            case UserLoanRequest::STATUS_WAIT_FOR_RISK:
                $return = [
                    'status' => self::$FULL_STATUS[self::FULL_STATUS_RISK],
                    'detail_status' => self::$FULL_STATUS_DETAIL[self::FULL_STATUS_RISK][$status]
                ];
                break;
            case UserLoanRequest::STATUS_APPLY:
            case UserLoanRequest::STATUS_FAILD:
                $return = [
                    'status' => self::$FULL_STATUS[self::FULL_STATUS_CREDIT],
                    'detail_status' => self::$FULL_STATUS_DETAIL[self::FULL_STATUS_CREDIT][$status]
                ];
                break;
            case UserLoanRequest::STATUS_TIME_OUT:
            case UserLoanRequest::STATS_RESTART:
                $return = [
                    'status' => self::$FULL_STATUS[self::FULL_STATUS_WAIT_LOAN],
                    'detail_status' => self::$FULL_STATUS_DETAIL[self::FULL_STATUS_WAIT_LOAN][$status]
                ];
                break;
            default:
                $return = [
                    'status' => '异常',
                    'detail_status' => '异常'
                ];
                break;
        }
        return $return;
    }


    /**
     * 新用户列表
     * @param $phone
     * @param $pageSize
     * @return array
     * @author luwei
     * @date 2019-01-14 20:52
     */
    public static function newUser($phone, $pageSize)
    {
        $userFields = [
            'u.id as user_id',
            'u.phone_num',
            'u.source',
            'u.created_at as register_time',
            'ulr.status as status'
        ];
        $logsFields = [
            'logs.login_time'
        ];
        $wechatFields = [
            'we.openid'
        ];
        $fields = array_merge($userFields, $logsFields, $wechatFields);
//        $sub    = UserLoanRequest::query()->select(['user_id', DB::raw('max(id) as d')])->groupBy('user_id');
//        $data   = UserLoanRequest::query()->from(DB::raw('user_loan_requests tb1'))
//            ->join(DB::raw("({$sub->toSql()}) as tb2"), function ($join) {
//                $join->on('tb1.user_id', '=', 'tb2.user_id')->on('tb1.id', '=', 'tb2.d');
//            })->with('userCert', 'stepLog')
        $data = User::select($fields)->from('users as u')
            ->when($phone, function ($query) use ($phone) {
                $query->where('u.phone_num', $phone);
            })
            ->leftJoin('user_loan_requests as ulr', 'u.id', 'ulr.user_id')
            ->leftJoin('user_login_logs as logs', 'u.id', 'logs.user_id')
            ->leftJoin('user_wechats as we', 'u.id', 'we.uid')
            ->where(function ($query) {
                $query->where(function ($q) {
                    $q->whereNull('ulr.status')->orWhere('ulr.status', 0);
                })->where(function ($q) {
                    $q->whereNull('ulr.current')->orWhere('ulr.current', 1);
                });
            })
            ->paginate($pageSize);
        return [
            'data' => $data->items(),
            'total' => $data->total()
        ];
    }

    public static function getHashKey()
    {
        return 'users:token';
    }

    /**
     * Description:更新redis中当前用户token记录，拉黑旧的token
     * Author: liuju
     * DateTime: 2019-01-06 15:29
     * @param $token
     */
    public static function updateTokenRecord($user, $token)
    {
        $hashKey = self::getHashKey();
        $key = $user->phone_num . ':token';
        $oldToken = Redis::hGet($hashKey, $key);
        if ($oldToken && $oldToken !== $token && JWTAuth::setToken($oldToken)->check()) {
            JWTAuth::setToken($oldToken)->invalidate();
        }
        Redis::hMset($hashKey, $key, $token);
    }

    /**
     * Description:用户与全局状态一对一关联
     * Author: Sam
     * DateTime: 2019/1/6 14:28
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
    public function globalStatus()
    {
        return $this->hasOne(UserGlobal::class, 'uid', 'id');
    }

    /**
     * Description:新增用户
     * Author: Sam
     * DateTime: 2019/1/6 21:10
     * @param $data
     * @return User
     * @throws GeneralException
     */
    public static function createUser($data)
    {
        DB::beginTransaction();
        try {
            /**
             * @var $user User
             */
            $user = User::create($data);

            $user->globalStatus()->create(['uid' => $user->id, 'global_status' => 0]);

            DB::commit();
            return $user;
        } catch (Exception $exception) {
            DB::rollBack();
            SamLogFacade::debug('创建用户失败：'.$exception->getMessage());
            throw new GeneralException('服务器错误');
        }
    }

    /**
     * Description:获取用户能不能开始录入认证信息
     * Author: Sam
     * DateTime: 2019/1/6 21:46
     * @return bool
     */
    public function getLoanAbleAttribute()
    {
        Carbon::setLocale('zh');
        $last_request_fail_time = UserGlobal::byUid($this->id)->value('last_request_fail_time');
        if (empty($last_request_fail_time)) {
            return true;
        }
        $months = SettingLoan::getBlacklistTime();
        $check_time = Carbon::parse('-' . $months . 'months');
        $fail_time = Carbon::parse($last_request_fail_time);
        if ($check_time->lt($fail_time)) {
            $able_time = $fail_time->addMonth($months);
            return $able_time->diffForHumans(Carbon::now());
        }
        return true;
    }

    /**
     * Description:更新用户当前绑定的银行卡
     * Author: Sam
     * DateTime: 2019/1/11 12:04
     * @param UserBankCard $bank_card
     */
    public static function UpdateUsingBankCard(UserBankCard $bank_card)
    {
        Log::debug('UpdateUsingBankCard data:'.json_encode($bank_card->toArray()));
        if ($bank_card->is_credit == UserBankCard::CREDIT_NO) {
            $user = User::find($bank_card->uid);
            $user->using_bank_card = $bank_card->id;
            $user->save();
        }
    }

    /**
     * 用户列表导出
     * @param bool $status 父状态
     * @param bool $childStatus 子状态
     * @param $name
     * @param int $pageSize
     * @return mixed
     * @throws GeneralException
     * @author luwei
     * @date 2019-01-07 21:06
     */
    public static function userListExport($status = false, $childStatus = false, $name) {
        $data   = self::userListData($status,$childStatus,$name,10,true);
        $return = [];
        foreach ($data as $v) {
            //处理授信信息
            $loanInfo = UserLoanRequest::getResource($v);
            $status   = $loanInfo['status'];
            unset($loanInfo['status']);

            $status = self::dealSpecStatus($status);

            //历史借次
            $count    = LoanApply::byUid($v->user_id)->where('loan_status', LoanApply::LOAN_STATUS_SUCCESS)->count();
            $text = self::dealDetailStatus($status, $loanInfo['id']);
            $detailStatusText = $text['detail_status'];
            $statusText = $text['status'];
            $return[] = [
                'id'                 => $v->id,
                'user_id'            => $loanInfo['user_id'],
                'name'               => $loanInfo['name'],
                'trade_id'           => $loanInfo['trade_id'],
                'card_num'           => $loanInfo['card_num'],
                'valid_at'           => $loanInfo['valid_at'],
                'apply_time'         => $loanInfo['apply_time'],
                'count'              => $count,
                'phone'              => optional(optional($v->user)->phone_num),
                'source'             => optional(optional($v->user)->source),
                'status'             => $status,
                'status_text'        => $statusText,
                'detail_status_text' => $detailStatusText
            ];
        }
        return $return;
    }

    /**
     * 新用户列表导出
     * @param $phone
     * @param $pageSize
     * @return array
     * @author luwei
     * @date 2019-01-14 20:52
     */
    public static function newUserExport($phone)
    {
        $userFields = [
            'u.id as user_id',
            'u.phone_num',
            'u.source',
            'u.created_at as register_time',
            'ulr.status as status'
        ];
        $logsFields = [
            'logs.login_time'
        ];
        $wechatFields = [
            'we.openid'
        ];
        $fields       = array_merge($userFields, $logsFields, $wechatFields);
        $data = (new User())->setConnection('backend')->select($fields)->from('users as u')
            ->when($phone, function ($query) use ($phone) {
                $query->where('u.phone_num', $phone);
            })
            ->leftJoin('user_loan_requests as ulr', 'u.id', 'ulr.user_id')
            ->leftJoin('user_login_logs as logs', 'u.id', 'logs.user_id')
            ->leftJoin('user_wechats as we', 'u.id', 'we.uid')
            ->where(function ($query) {
                $query->where(function ($q) {
                    $q->whereNull('ulr.status')->orWhere('ulr.status', 0);
                })->where(function ($q) {
                    $q->whereNull('ulr.current')->orWhere('ulr.current', 1);
                });
            })
            ->get()->toArray();
        return $data;
    }

    /**
     * Description:根据年龄生成婚姻状态
     * Author: Sam
     * DateTime: 2019-01-26 13:00
     * @param $age
     * @return string
     */
    public static function getMaritalStatus($age)
    {
        if ($age <= 21) {
            return '0';
        }
        if ($age >= 22 && $age <= 25) {
            $data = [
                1 => [
                    'id' => 1,
                    'val' => '0',
                    'v' => 7,
                ],
                2 => [
                    'id' => 2,
                    'val' => '1',
                    'v' => 3,
                ],
            ];
            $key = self::getRand($data);
            return $data[$key]['val'];
        }
        if ($age >= 26 && $age <= 30) {
            $data = [
                1 => [
                    'id' => 1,
                    'val' => '0',
                    'v' => 3,
                ],
                2 => [
                    'id' => 2,
                    'val' => '1',
                    'v' => 7,
                ],
            ];
            $key = self::getRand($data);
            return $data[$key]['val'];
        }
        if ($age >= 31 && $age <= 40) {
            $data = [
                1 => [
                    'id' => 1,
                    'val' => '0',
                    'v' => 1,
                ],
                2 => [
                    'id' => 2,
                    'val' => '1',
                    'v' => 9,
                ],
            ];
            $key = self::getRand($data);
            return $data[$key]['val'];
        }
        if ($age >= 41) {
            return '1';
        }
    }

    /**
     * Description:生成用户邮箱
     * Author: Sam
     * DateTime: 2019-01-26 15:26
     * @param $name
     * @return string
     */
    public static function createEmail($name)
    {
        $data = [
            1 => [
                'id' => 1,
                'val' => '@163.com',
                'v' => 33,
            ],
            2 => [
                'id' => 2,
                'val' => '@qq.com',
                'v' => 33,
            ],
            3 => [
                'id' => 3,
                'val' => '@outlook.com',
                'v' => 34,
            ],
        ];
        $key = self::getRand($data);
        $mail = $data[$key]['val'];
        return $name . $mail;
    }

    /**
     * Description:根据概率抽取数据
     * Author: Sam
     * DateTime: 2019-01-26 13:29
     * @param $data
     * @return int|string
     */
    public static function getRand($data)
    {
        $arr = [];
        foreach ($data as $item) {
            $arr[$item['id']] = $item['v'];
        }

        $total = array_sum($arr);
        foreach ($arr as $key => $proCur) {
            $randNum = mt_rand(1, $total);
            if ($randNum <= $proCur) {
                $result = $key;
                break;
            } else {
                $total -= $proCur;
            }
        }
        return $result;
    }

    /**
     * Description:生成月收入
     * Author: Sam
     * DateTime: 2019-01-29 11:00
     * @param $amount "风控额度"
     * @return float|int
     */
    public static function createSalary($amount)
    {
        $salary = $amount  * 1.6;
        $salary = $salary < 5000 ? 5000 : abs($salary);
        return $salary;
    }

    /**
     * Description:生成工作年限
     * Author: Sam
     * DateTime: 2019-03-20 15:53
     * @param $age
     * @return int
     */
    public static function createWorkDuration($age)
    {
        return $age - 20 < 1 ? 1 : $age - 20;
    }

    /**
     * Description:生成单位性质
     * Author: Sam
     * DateTime: 2019-03-20 16:28
     */
    public static function createCompanyCategory()
    {

    }

    /**
     * Description:生成供养人口
     * Author: Sam
     * DateTime: 2019-03-20 16:29
     */
    public static function createSupportPopulation()
    {

    }

    /**
     * Description:生成单位所属行业
     * Author: Sam
     * DateTime: 2019-03-20 16:30
     */
    public static function createIndustry()
    {

    }

    /**
     * Description:生成社会身份
     * Author: Sam
     * DateTime: 2019-01-26 15:37
     * @param $age
     * @return string
     */
    public static function createPosition($age)
    {
        if ($age < 20) {
            return '04';
        }
        if ($age >= 20 && $age <= 30) {
            return '01';
        }
        if ($age >= 31 && $age <= 55) {
            $data = [
                1 => [
                    'id' => 1,
                    'val' => '01',
                    'v' => 9,
                ],
                2 => [
                    'id' => 2,
                    'val' => '07',
                    'v' => 1,
                ],
            ];
            $key = self::getRand($data);
            return $data[$key]['val'];
        }
        if ($age > 55) {
            return '06';
        }
    }


    /**
     * Description:检查用户能否开始新的授信
     * Author: Sam
     * DateTime: 2019-02-22 18:29
     * @return bool
     */
    public function canLoan()
    {
        /**
         * 检查有没有授信中的业务
         */
        $exist1 = UserLoanRequest::where('user_id', $this->id)
            ->whereIn('status', [UserLoanRequest::STATUS_WAIT_FOR_RISK, UserLoanRequest::STATUS_APPLY])
            ->where('current', UserLoanRequest::CURRENT_NOW)
            ->value('id');
        if ($exist1) {
            Log::debug('用户' . $this->id . '有授信中的业务');
            return false;
        }

        /**
         * 检查有没有放款中的业务
         */
        $exist2 = LoanApply::where('user_id', $this->id)
            ->whereIn('loan_status', LoanApply::CAN_NOT_LOAN)
            ->value('id');
        if ($exist2) {
            Log::debug('用户' . $this->id . '有放款中的业务');
            return false;
        }
        /**
         * 检查有没有还款中的业务
         */
        $exist3 = RepaySummary::checkRepay($this->id);
        if (!$exist3) {
            Log::debug('用户' . $this->id . '有还款中的业务');
            return false;
        }
        return true;
    }


    /**
     * Description:通过日期和小时来获取来源
     * Author: liuju
     * DateTime: 2019-03-07 20:53
     * @param $date
     * @param $hour
     * @return array
     */
    public static function getSourceByDateHour($date, $hour)
    {
        $data = self::whereDate('created_at', $date)
            ->whereTime('created_at', $hour . ':00')
            ->whereTime('created_at', $hour . ':59')
            ->groupBy('source')
            ->pluck('source')->toArray();
        foreach ($data as $key => $value) {
            if (!$value) {
                $data[$key] = 0;
            }
        }
        return $data;
    }
}
